home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / ipServer / ip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-09  |  53.4 KB  |  1,953 lines

  1. /* 
  2.  * ip.c --
  3.  *
  4.  *      Routines to handle the IP protocol. IP packets that are received
  5.  *      from the network layer are validated and passed to the next
  6.  *      protocol layer. If the packet is fragmented, it is reassembled
  7.  *      before passed to the next layer. This file also contains
  8.  *      routines to format IP header in a packet and to send the packet to
  9.  *      the network for output. The packet may be sent in fragments if it
  10.  *      is too large for the network.
  11.  *
  12.  *    The IP protocol specification used by the routines in this file
  13.  *    is RFC 791 "Internet Protocol", Sept. 1981.
  14.  *
  15.  *
  16.  *    Based on 4.3 BSD code:
  17.  *    "@(#)ip_input.c  7.9 (Berkeley) 3/15/88"
  18.  *    "@(#)ip_output.c 7.9 (Berkeley) 3/15/88"
  19.  *
  20.  * Copyright 1987 Regents of the University of California
  21.  * All rights reserved.
  22.  * Permission to use, copy, modify, and distribute this
  23.  * software and its documentation for any purpose and without
  24.  * fee is hereby granted, provided that the above copyright
  25.  * notice appear in all copies.  The University of California
  26.  * makes no representations about the suitability of this
  27.  * software for any purpose.  It is provided "as is" without
  28.  * express or implied warranty.
  29.  */
  30.  
  31. #ifndef lint
  32. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/ip.c,v 1.9 89/10/22 12:15:17 nelson Exp $ SPRITE (Berkeley)";
  33. #endif not lint
  34.  
  35.  
  36. #include "sprite.h"
  37. #include "ipServer.h"
  38. #include "stat.h"
  39. #include "ip.h"
  40. #include "icmp.h"
  41. #include "route.h"
  42. #include "raw.h"
  43.  
  44. #include "list.h"
  45. #include "spriteTime.h"
  46. #include "fs.h"
  47.  
  48. /*
  49.  * Information needed to aid in reassembly of a datagram from its fragments. 
  50.  *
  51.  * The fragInfoList is a list of DgramFragInfo elements with one element
  52.  * per fragmented datagram. The fragments are kept on the dataList linked
  53.  * list within each DgramFragInfo element.  All fragments of a datagram
  54.  * have the same source, destination, protocol and identification fields
  55.  * in their IP headers.  If the datagram isn't reassembled before the
  56.  * timeToLive field goes to 0, all fragments are freed and the DgramFragInfo
  57.  * element is removed from the fragInfoList.
  58.  */
  59.  
  60. typedef struct {
  61.     List_Links        links;        /* Links to next and prev. items. */
  62.  
  63.     /*
  64.      * The following 4 fields in the IP header uniquely identify the datagram. 
  65.      * A fragment belongs to this datagram if all 4 fields match.
  66.      */
  67.     Net_InetAddress    source;        /* Sender of packet. */
  68.     Net_InetAddress    dest;        /* Destination of packet. */
  69.     unsigned char    protocol;    /* Protocol. */
  70.     unsigned short    ident;        /* Datagram ID. */
  71.  
  72.     int            numFrags;    /* Number of fragments. */
  73.     int            timeToLive;    /* # of seconds before the fragments 
  74.                      * are dropped. */
  75.     List_Links        dataList;    /* List head of data info elements for 
  76.                      * fragments that have arrived. */
  77. } DgramFragInfo;
  78.  
  79. /*
  80.  * List head of the list of DgramFragInfo elements.
  81.  */
  82. static List_Links    fragInfoList;
  83.  
  84.  
  85. /*
  86.  * Information about a particular fragment within a datagram.
  87.  *
  88.  * Each fragment of a datagram has one of these structures in the 
  89.  * dataList list of the DgramFragInfo element.
  90.  */
  91. typedef struct {
  92.     List_Links        links;        /* Links to next and prev. items. */
  93.     unsigned short    fragOffset;    /* Offset from the beginning of 
  94.                      * the datagram for the data in
  95.                      * this frgament. */
  96.     int            dataOffset;    /* Offset from beginning of this 
  97.                      * fragment data where usable data 
  98.                      * starts. */
  99.     int            dataLen;    /* Size in bytes of usable data. */
  100.     IPS_Packet        fragPacket;    /* Address of fragment packet. */
  101. } FragDataInfo;
  102.  
  103. /*
  104.  * Amount of time between calls to FragTimeoutHandler.
  105.  */
  106. static Time    fragTimeout = { 1, 0 };
  107.  
  108.  
  109. /*
  110.  * The protocolCallback array of functions is used to pass an IP packet
  111.  * to the next protocol layer. A higher-level protocol establishes a 
  112.  * callback using IP_SetProtocolHandler. The maximum number of callbacks is 
  113.  * 255 since the protocol field in the IP header 8 bits wide.
  114.  */
  115.  
  116. #define MAX_PROTOCOL_NUM    255
  117. static void (*protocolCallback[MAX_PROTOCOL_NUM+1])();
  118.  
  119. /*
  120.  * Forward declarations.
  121.  */
  122. static Boolean        ReassemblePacket();
  123. static ReturnStatus    ProcessOptions();
  124. static void        ForwardPacket();
  125. static DgramFragInfo    *FreeFragments();
  126. static void        SaveRoute();
  127. static void        FragTimeoutHandler();
  128. static int         CopyHeader();
  129. static Boolean        CanForward();
  130.  
  131. #ifdef DEBUG
  132. static void         TestInputProc();
  133. #endif
  134.  
  135. /*
  136.  * Macro to swap the fragOffset field.
  137.  */
  138. #define SWAP_FRAG_OFFSET_HOST_TO_NET(ptr) { \
  139.     short    *shortPtr; \
  140.     shortPtr = ((short *)&ptr->ident) + 1; \
  141.     *shortPtr = Net_HostToNetShort(*shortPtr); \
  142.  
  143. #define SWAP_FRAG_OFFSET_NET_TO_HOST(ptr) { \
  144.     short    *shortPtr; \
  145.     shortPtr = ((short *)&ptr->ident) + 1; \
  146.     *shortPtr = Net_NetToHostShort(*shortPtr); \
  147.  
  148.  
  149. /*
  150.  *----------------------------------------------------------------------
  151.  *
  152.  * IP_MemBin --
  153.  *
  154.  *    Optimize memory allocation of data structures that are dynamically
  155.  *    allocated by IP.
  156.  *
  157.  * Results:
  158.  *    None.
  159.  *
  160.  * Side effects:
  161.  *    Calls Mem_Bin.
  162.  *
  163.  *----------------------------------------------------------------------
  164.  */
  165.  
  166. void
  167. IP_MemBin()
  168. {
  169.     Mem_Bin(sizeof(DgramFragInfo));
  170.     Mem_Bin(sizeof(FragDataInfo));
  171.     Mem_Bin(sizeof(Net_IPHeader));
  172.     Mem_Bin(NET_ETHER_MAX_BYTES);
  173. }
  174.  
  175. /*
  176.  *----------------------------------------------------------------------
  177.  *
  178.  * IP_Init --
  179.  *
  180.  *    Initializes the DgramFragInfo list. This routine must be
  181.  *    called before any packets are processed. Arranges to have 
  182.  *    FragTimeoutHandler to be called at regular intervals.
  183.  *
  184.  * Results:
  185.  *    None.
  186.  *
  187.  * Side effects:
  188.  *    The DgramFragInfo list is initialized. A timeout handler is
  189.  *    created.
  190.  *
  191.  *----------------------------------------------------------------------
  192.  */
  193.  
  194. void
  195. IP_Init()
  196. {
  197.     List_Init(&fragInfoList);
  198.  
  199.     (void) Fs_TimeoutHandlerCreate(fragTimeout, TRUE, FragTimeoutHandler, 
  200.         (ClientData) 0);
  201. }
  202.  
  203.  
  204. /*
  205.  *----------------------------------------------------------------------
  206.  *
  207.  * IP_SetProtocolHandler --
  208.  *
  209.  *    Each IP packet has a protocol field that specifies the next protocol
  210.  *    layer to be called once the IP input routine has finished with
  211.  *    the datagram.  This routine establishes the procedure that will be
  212.  *    called for the given protocol.
  213.  *
  214.  *    The proc parameter should be declared as follows:
  215.  *
  216.  *    void
  217.  *    Proc(netID, packetPtr)
  218.  *        Rte_NetID    netID;
  219.  *        IPS_Packet    *packetPtr;
  220.  *    {
  221.  *    }
  222.  *
  223.  *    It is responsible for freeing the packet once it is done with it.
  224.  *
  225.  * Results:
  226.  *    None.
  227.  *
  228.  * Side effects:
  229.  *    The table of protocol callbacks is updated.
  230.  *
  231.  *----------------------------------------------------------------------
  232.  */
  233.  
  234. void
  235. IP_SetProtocolHandler(protocol, proc)
  236.     int        protocol;    /* Assigned protocol number from RFC 1010. */
  237.     void    (*proc)();    /* Procedure to call to handle packets with
  238.                  * the protocol #. */
  239. {
  240.     if (protocol < 0 || protocol > MAX_PROTOCOL_NUM) {
  241.     (void) fprintf(stderr, "Warning: IP_SetProtocolHandler: bad protocol # (%d)\n",
  242.             protocol);
  243.     return;
  244.     }
  245.     if (proc == NULL) {
  246.     (void) fprintf(stderr, 
  247.         "Warning: IP_SetProtocolHandler: NULL procedure address\n");
  248.     }
  249.     protocolCallback[protocol] = proc;
  250. }
  251.  
  252.  
  253. /*
  254.  *----------------------------------------------------------------------
  255.  *
  256.  * IP_AcceptedProtocol --
  257.  *
  258.  *    Determine if a IP protocol has a handler established for it.  This
  259.  *    is used at open time in order to deny opening an IP protocol that
  260.  *    is not implemented.
  261.  *
  262.  * Results:
  263.  *    TRUE if a callback has been installed for the protocol.
  264.  *
  265.  * Side effects:
  266.  *    None.
  267.  *
  268.  *----------------------------------------------------------------------
  269.  */
  270.  
  271. Boolean
  272. IP_AcceptedProtocol(protocol)
  273.     int        protocol;    /* Assigned protocol number from RFC 1010. */
  274. {
  275.     if (protocol < 0 || protocol > MAX_PROTOCOL_NUM) {
  276.     return(FALSE);
  277.     } else if (protocolCallback[protocol] != NULL) {
  278.     return(TRUE);
  279.     } else {
  280.     return(FALSE);
  281.     }
  282. }
  283.  
  284. /*
  285.  *----------------------------------------------------------------------
  286.  *
  287.  * IP_Input --
  288.  *
  289.  *    The main routine to deal with new IP packets from the network.
  290.  *    The packet is checked to make sure that it has the proper sizes
  291.  *    and that it has not been corrupted. The packet's destination is 
  292.  *    checked to see if it is for us or whether it needs to be forwarded
  293.  *    to the appropriate gateway. IP options processing and fragment 
  294.  *    reassembly is also initiated here.  Once processed, the packet 
  295.  *    may be handed to the next protocol layer.
  296.  *
  297.  *    Terminology: a packet is the data received from the network.
  298.  *    It may a complete IP datagram or a fragment of a datagram.
  299.  *
  300.  * Results:
  301.  *    SUCCESS    - The packet was processed successfully or was a fragment. 
  302.  *          The caller can NOT deallocate the packet memory.
  303.  *    FAILURE    - The packet was malformed or was not used. The caller 
  304.  *          must deallocate the packet memory.
  305.  *
  306.  * Side effects:
  307.  *    The fragment queue may be changed. Various statistics counters 
  308.  *    are incremented.
  309.  *
  310.  *
  311.  *    The following fields are converted from network order to host order.
  312.  *     - totalLen
  313.  *     - ident
  314.  *     - offset + flags
  315.  *     - checksum
  316.  *     - source
  317.  *     - dest
  318.  *    They must be changed back if the packet needs to be output 
  319.  *    to the network.
  320.  *
  321.  *
  322.  *----------------------------------------------------------------------
  323.  */
  324.  
  325. ReturnStatus
  326. IP_Input(netID, packetPtr)
  327.     Rte_NetID    netID;        /* ID of network interface that this packet
  328.                  * arrived on. */
  329.     IPS_Packet    *packetPtr;    /* Packet layout descriptor. */
  330. {
  331.     register Net_IPHeader    *ipHeaderPtr;
  332.     register int        headerLenInBytes;
  333.  
  334.  
  335.     stats.ip.totalRcv++;
  336.  
  337.     if (packetPtr->ipLen < sizeof(Net_IPHeader)) {
  338.     stats.ip.shortPacket++;
  339.     if (ips_Debug) {
  340.         fprintf(stderr, "IP_Input: Short packet, len=%d\n", 
  341.                 packetPtr->ipLen);
  342.     }
  343.     return(FAILURE);
  344.     }
  345.  
  346.     ipHeaderPtr =  packetPtr->ipPtr;
  347.     headerLenInBytes = ipHeaderPtr->headerLen * 4;
  348.  
  349.     if (headerLenInBytes < sizeof(Net_IPHeader)) {
  350.     stats.ip.shortHeader++;
  351.     if (ips_Debug) {
  352.         fprintf(stderr, "IP_Input: Short header, len=%d\n", 
  353.                 headerLenInBytes);
  354.     }
  355.     return(FAILURE);
  356.     }
  357.  
  358.     /*
  359.      * See if the header checksum is ok. RFC791 says the header checksum 
  360.      * is computed as if ipHeaderPtr->checksum is 0 but we recompute it with
  361.      * whatever value that's there. If the packet is good, then the sum not
  362.      * including ipHeaderPtr->checksum should be the 1's complement of 
  363.      * ipHeaderPtr->checksum and when added together (during the checksum 
  364.      * computation), they should equal 0.
  365.      */
  366.     if (Net_InetChecksum(headerLenInBytes, (Address) ipHeaderPtr) != 0) {
  367.     stats.ip.badChecksum++;
  368.     if (ips_Debug) {
  369.         fprintf(stderr, "IP_Input: Bad check sum\n");
  370.     }
  371.     return(FAILURE);
  372.     }
  373.  
  374.     ipHeaderPtr->totalLen = Net_NetToHostShort(ipHeaderPtr->totalLen);
  375.     ipHeaderPtr->ident    = Net_NetToHostShort(ipHeaderPtr->ident);
  376.     SWAP_FRAG_OFFSET_NET_TO_HOST(ipHeaderPtr);
  377.  
  378.     /*
  379.      * Change the length in the packet descriptor to the true length.
  380.      * The previous value for the length was calculated from the
  381.      * packet size from the network and that might have been too large.
  382.      */
  383.     packetPtr->ipLen = ipHeaderPtr->totalLen;
  384.  
  385.     if (ipHeaderPtr->totalLen < ipHeaderPtr->headerLen) {
  386.     stats.ip.shortLen++;
  387.     if (ips_Debug) {
  388.         fprintf(stderr, "IP_Input: Short length, len=%d\n", 
  389.                 ipHeaderPtr->totalLen);
  390.     }
  391.     return(FAILURE);
  392.     }
  393.  
  394.     if (headerLenInBytes > sizeof(Net_IPHeader)) {
  395.     /*
  396.      * Process the options that follow the basic IP header.
  397.      */
  398.     if (!ProcessOptions(headerLenInBytes, ipHeaderPtr)) {
  399.         if (ips_Debug) {
  400.         fprintf(stderr, "IP_Input: Bad options\n");
  401.         }
  402.         return(FAILURE);
  403.     }
  404.     }
  405.  
  406.     if (ips_Debug) {
  407.     (void) fprintf(stderr, 
  408.             "IP Input: %d bytes, prot %d <%x> <-- <%x,#%d> flags %x\n",
  409.             packetPtr->ipLen,
  410.             ipHeaderPtr->protocol,
  411.             Net_NetToHostInt(ipHeaderPtr->dest), 
  412.             Net_NetToHostInt(ipHeaderPtr->source),
  413.             ipHeaderPtr->ident,
  414.             ipHeaderPtr->flags);
  415.  
  416.     }
  417.  
  418.  
  419.     /*
  420.      * See if the packet is for us. If it isn't then forward it to
  421.      * the appropriate host.
  422.      */
  423.     
  424.     if (!Rte_AddrIsForUs(ipHeaderPtr->dest)) {
  425.     stats.ip.forwards++;
  426.     if (ips_Debug) {
  427.         fprintf(stderr, "IP_Input: Forwarding packet\n");
  428.     }
  429.     ForwardPacket(packetPtr);
  430.     return(FAILURE);
  431.     }
  432.  
  433.  
  434.     /*
  435.      * Fragmentation test: 
  436.      * See if this packet is a complete datagram or a fragment of one.
  437.      * If it's a fragment, then search the queue and try to reassemble the
  438.      * complete datagram.  If it's a complete datagram already, then 
  439.      * don't search the queue; even though there may be fragments for the
  440.      * datagram on the queue, let the timeout routine remove them.
  441.      */
  442.     if ((ipHeaderPtr->flags & NET_IP_MORE_FRAGS) ||
  443.     (ipHeaderPtr->fragOffset != 0)) {
  444.  
  445.     register DgramFragInfo    *fragInfoPtr;
  446.     Boolean    foundFrags;
  447.  
  448.     stats.ip.fragsRcv++;
  449.     if (ips_Debug) {
  450.         fprintf(stderr, "IP_Input: Received fragment, offset=%d\n",
  451.             ipHeaderPtr->fragOffset);
  452.     }
  453.  
  454.     foundFrags = FALSE;
  455.     LIST_FORALL(&fragInfoList, (List_Links *) fragInfoPtr) {
  456.         if ((ipHeaderPtr->ident == fragInfoPtr->ident) &&
  457.         (ipHeaderPtr->protocol == fragInfoPtr->protocol) &&
  458.         (ipHeaderPtr->source == fragInfoPtr->source) &&
  459.         (ipHeaderPtr->dest == fragInfoPtr->dest)) {
  460.         foundFrags = TRUE;
  461.         break;
  462.         }
  463.     }
  464.     if (!foundFrags) {
  465.         /*
  466.          * First fragment to arrive so there's no information yet.
  467.          * ReassemblePacket will create a list for this datagram.
  468.          */
  469.         if (ips_Debug) {
  470.         fprintf(stderr, "IP_Input: First fragment\n");
  471.         }
  472.         fragInfoPtr = (DgramFragInfo *) NULL;
  473.     }
  474.  
  475.     if (!ReassemblePacket(fragInfoPtr, packetPtr)) {
  476.         /*
  477.          * The fragment did not complete the packet.
  478.          */
  479.         return(SUCCESS);
  480.     }
  481.     if (ips_Debug) {
  482.         fprintf(stderr, "IP_Input: Fragment completes packet\n");
  483.     }
  484.     stats.ip.fragsReass++;
  485.     }
  486.  
  487.     /*
  488.      * IP Processing is now complete. Pass the datagram to the next protocol
  489.      * for additional processing.  If a callback has not been established for
  490.      * a protocol, give the datagram to the raw socket layer. 
  491.      */
  492.  
  493.     if ((ipHeaderPtr->protocol <= MAX_PROTOCOL_NUM) &&
  494.     (protocolCallback[ipHeaderPtr->protocol] != NULL)) {
  495.  
  496.      (*protocolCallback[ipHeaderPtr->protocol]) (netID, packetPtr);
  497.  
  498.     } else {
  499.     Raw_Input((int)ipHeaderPtr->protocol, ipHeaderPtr->source, 
  500.             ipHeaderPtr->dest, packetPtr);
  501.     return(FAILURE);    /* So caller will deallocate the packet. */
  502.     }
  503.     return(SUCCESS);
  504. }
  505.  
  506. /*
  507.  *----------------------------------------------------------------------
  508.  *
  509.  * FragTimeoutHandler --
  510.  *
  511.  *    Examines the fragment queue to see if any fragments should be
  512.  *    discarded because they have not been reassembled within a certain
  513.  *    amount of time. This routine is called from the Fs_Dispatch's
  514.  *    timeout mechanism.
  515.  *
  516.  * Results:
  517.  *    None.
  518.  *
  519.  * Side effects:
  520.  *    The fragment info list may be changed.
  521.  *
  522.  *----------------------------------------------------------------------
  523.  */
  524.  
  525. /*ARGSUSED*/
  526. static void
  527. FragTimeoutHandler(data, time)
  528.     ClientData    data;        /* ignored. */
  529.     Time    time;        /* ignored. */
  530. {
  531.     register DgramFragInfo    *fragInfoPtr;
  532.  
  533.     stats.ip.fragTimeouts++;
  534.  
  535.     fragInfoPtr = (DgramFragInfo *) List_First(&fragInfoList);
  536.     while (!List_IsAtEnd(&fragInfoList, (List_Links *) fragInfoPtr)) {
  537.     if (fragInfoPtr->timeToLive <= 0) {
  538.         /*
  539.          * FreeFragments will remove the element from the list
  540.          * but it will return the pointer to the next element
  541.          * so the while loop will work.
  542.          */
  543.  
  544.         if (ips_Debug) {
  545.         fprintf(stderr, "IP Frag timeout: src <%x, #%d>\n",
  546.             fragInfoPtr->source, fragInfoPtr->ident);
  547.         }
  548.  
  549.         fragInfoPtr = FreeFragments(fragInfoPtr);
  550.  
  551.         stats.ip.fragsTimedOut++;
  552.  
  553.     } else {
  554.         fragInfoPtr->timeToLive--;
  555.         fragInfoPtr = (DgramFragInfo *) 
  556.                 List_Next((List_Links *) fragInfoPtr);
  557.     }
  558.  
  559.     }
  560. }
  561.  
  562.  
  563. /*
  564.  *----------------------------------------------------------------------
  565.  *
  566.  * ReassemblePacket --
  567.  *
  568.  *    Given a packet that is a fragment of a datagram, try to reassemble
  569.  *    a complete datagram.
  570.  *
  571.  * Results:
  572.  *    TRUE        - the datagram was reassembled.
  573.  *    FALSE        - the fragment did not complete the datagram.
  574.  *
  575.  * Side effects:
  576.  *    The fragment will be added to the list of frgaments for this
  577.  *    datagram. If all fragments for the datagram have arrived, they
  578.  *    are consolidated into 1 buffer and the memory held by the fragments 
  579.  *    is freed.
  580.  *
  581.  *----------------------------------------------------------------------
  582.  */
  583.  
  584. static Boolean
  585. ReassemblePacket(fragInfoPtr, packetPtr)
  586.     register DgramFragInfo *fragInfoPtr;/* Info about existing fragments
  587.                      * for this datagram. */
  588.     IPS_Packet    *packetPtr;        /* Addr of ptr to Fragment (in) -- Addr
  589.                      * of ptr to completed datagram (out).*/
  590. {
  591.     register FragDataInfo    *dataPtr;    /* Ptr to element on the
  592.                          * fragment queue. */
  593.     register FragDataInfo    *newDataPtr;
  594.     register List_Links        *fragDataListPtr;
  595.     register Net_IPHeader    *ipHeaderPtr;
  596.     register int        fragOffset;
  597.     Address            ptr;
  598.     Boolean            first;
  599.     int                next;
  600.     int                lastByte;
  601.  
  602.     ipHeaderPtr = packetPtr->ipPtr;
  603.  
  604.     /*
  605.      * The fragOffset "is measured in units of 8 octets (64 bits)".
  606.      * It is necessary to use it as # of bytes, hence the multiplication
  607.      * by 8.  Note that we already byte swapped it before this routine was
  608.      * called.
  609.      */
  610.     fragOffset = ipHeaderPtr->fragOffset * 8;
  611.  
  612.     /*
  613.      * For the first fragment, allocate the fragment info data structure 
  614.      * and initialize it.
  615.      */
  616.     if (fragInfoPtr == (DgramFragInfo *) NULL) {
  617.     fragInfoPtr = (DgramFragInfo *) malloc(sizeof(DgramFragInfo));
  618.     fragInfoPtr->source    = ipHeaderPtr->source;
  619.     fragInfoPtr->dest    = ipHeaderPtr->dest;
  620.     fragInfoPtr->ident    = ipHeaderPtr->ident;
  621.     fragInfoPtr->protocol    = ipHeaderPtr->protocol;
  622.     fragInfoPtr->numFrags    = 0;
  623.     fragInfoPtr->timeToLive    = NET_IP_MAX_FRAG_TTL;
  624.     fragDataListPtr =  &(fragInfoPtr->dataList);
  625.     dataPtr = (FragDataInfo    *) fragDataListPtr;
  626.     List_Init(fragDataListPtr);
  627.  
  628.     List_InitElement((List_Links *) fragInfoPtr);
  629.     List_Insert((List_Links *) fragInfoPtr, LIST_ATFRONT(&fragInfoList));
  630.     } else {
  631.  
  632.     fragDataListPtr = &(fragInfoPtr->dataList);
  633.  
  634.     /*
  635.      * Insert a new fragment into the appropriate spot in the fragment
  636.      * list. Depending on the location, new fragments may or may not
  637.      * replace data in existing fragments.  (Note: this is contrary
  638.      * to RFC791 which says data in an arriving fragment should
  639.      * replace existing data. The algorithm to do that is a bit more
  640.      * complex than the one use below.)
  641.      *
  642.      * Step 1: search the list to find the first existing fragment
  643.      * that begins after the new fragment. When the loop is exited via
  644.      * the break, dataPtr will point to this existing fragment.
  645.      * If we don't take the break, dataPtr will point to the head of 
  646.      * the list and the new fragment belongs at the end of the list.
  647.      */
  648.  
  649.     LIST_FORALL(fragDataListPtr, (List_Links *) dataPtr) {
  650.         /*
  651.          * Find the first existing fragment that begins after 
  652.          * the new fragment.
  653.          */ 
  654.         if (fragOffset < dataPtr->fragOffset) {
  655.         break;
  656.         }
  657.     }
  658.  
  659.     /*
  660.      * Step 2: The new fragment is before dataPtr and after
  661.      * newDataPtr. newDataPtr could be the head of list which means
  662.      * the new fragment fits in front of all the other fragments.
  663.      * dataPtr could be the list head which means that the new
  664.      * fragment goes at the end of the list.
  665.      */
  666.  
  667.     newDataPtr = (FragDataInfo *) (List_Prev((List_Links *)dataPtr));
  668.  
  669.     if (!List_IsAtEnd(fragDataListPtr, (List_Links *)newDataPtr)) {
  670.  
  671.         int i = newDataPtr->fragOffset + newDataPtr->dataLen - 
  672.                 fragOffset;
  673.         /*
  674.          * "if (i > 0)" ==  if (fragOffset < last byte in preceeding 
  675.          * fragment) then the new fragment overlaps or is contained in 
  676.          * the preceeding fragment.
  677.          */
  678.  
  679.         if (i > 0) {
  680.         if (i >= ipHeaderPtr->totalLen) {
  681.             /*
  682.              * The new fragment is totally contained in the preceeding 
  683.              * fragment so drop the new fragment. 
  684.              *
  685.              * (If the new data were to replace the old, the preceeding 
  686.              * fragment would have to be split or the data from 
  687.              * the new fragment copied into the preceeding fragment.)
  688.              */
  689.  
  690.             if (ips_Debug) {
  691.             fprintf(stderr, "ReassemblePacket: Frag dropped\n");
  692.             }
  693.             stats.ip.fragsDropped++;
  694.             free(packetPtr->base);
  695.             return(FALSE);
  696.  
  697.         } else {
  698.             /*
  699.              * The end of the preceeding fragment needs to be trimmed 
  700.              * because the new fragment replaces that data.
  701.              * (4.3BSD keeps the old data and trims the front of
  702.              * the new fragment).
  703.              */
  704.              newDataPtr->dataLen -= i;
  705.         }
  706.         }
  707.     }
  708.  
  709.     /*
  710.      * Step 3:  see if the succeeding fragments need to be trimmed 
  711.      * because the end of the new fragment partially or completely 
  712.      * overlaps them.
  713.      */
  714.  
  715.     lastByte = fragOffset + ipHeaderPtr->totalLen;
  716.     while ((!List_IsAtEnd(fragDataListPtr, (List_Links *)dataPtr)) &&
  717.            (dataPtr->fragOffset < lastByte)) {
  718.  
  719.         if ((dataPtr->fragOffset + dataPtr->dataLen) < lastByte) {
  720.         /*
  721.          * The new fragment covers the old fragment so the
  722.          * old one can be freed.
  723.          */
  724.  
  725.         newDataPtr =  /* temp. holder */
  726.             (FragDataInfo *) (List_Next((List_Links *)dataPtr));
  727.         List_Remove((List_Links *)dataPtr);
  728.         free((char *) dataPtr->fragPacket.base);
  729.         free((char *) dataPtr);
  730.         dataPtr = newDataPtr;
  731.  
  732.         } else {
  733.         /*
  734.          * The new fragment covers some, but not all, of the old 
  735.          * fragment. Trim data from the start of the old one. 
  736.          * At this point we are also done trimming.
  737.          */
  738.         int trimAmt = lastByte - dataPtr->fragOffset;
  739.  
  740.         dataPtr->fragOffset    += trimAmt;
  741.         dataPtr->dataOffset    += trimAmt;
  742.         dataPtr->dataLen    -= trimAmt;
  743.         break;
  744.         }
  745.     }
  746.     }
  747.  
  748.     /*
  749.      * Insert the new fragment into the list of received fragments.
  750.      */
  751.  
  752.     fragInfoPtr->numFrags++;
  753.     newDataPtr = (FragDataInfo *) malloc(sizeof(FragDataInfo));
  754.     newDataPtr->fragOffset    = fragOffset;
  755.     newDataPtr->dataOffset    = ipHeaderPtr->headerLen * 4;
  756.     newDataPtr->dataLen        = ipHeaderPtr->totalLen -newDataPtr->dataOffset;
  757.     newDataPtr->fragPacket    = *packetPtr;
  758.  
  759.     List_InitElement((List_Links *) newDataPtr);
  760.     List_Insert((List_Links *)newDataPtr, LIST_BEFORE((List_Links *) dataPtr));
  761.  
  762.  
  763.     /*
  764.      * Now scan the data list for this datagram to see if all the 
  765.      * fragments have been received. "Next" is the next expected fragment
  766.      * offset.
  767.      */
  768.  
  769.     next = 0;
  770.     LIST_FORALL(fragDataListPtr, (List_Links *) dataPtr) {
  771.     if (dataPtr->fragOffset != next) {
  772.         /*
  773.          * Oops! Found a hole so the datagram is not yet complete.
  774.          */
  775.         if (ips_Debug) {
  776.         fprintf(stderr, "ReassemblePacket: Incomplete datagram\n");
  777.         }
  778.         return(FALSE);
  779.     } else {
  780.         next += dataPtr->dataLen;
  781.     }
  782.     }
  783.  
  784.     /*
  785.      * All the fragments are contiguous but we have to check if the
  786.      * last fragment has been received. This is done by checking 
  787.      * the NET_IP_MORE_FRAGS bit in the header of the queue's last fragment.
  788.      * If that bit is set, then the reassembly is not yet complete.
  789.      *
  790.      * (dataPtr should point to the head of the list so we need to look
  791.      * at the previous element.)
  792.      */
  793.  
  794.     newDataPtr = (FragDataInfo *) (List_Prev((List_Links *)dataPtr));
  795.     if (newDataPtr->fragPacket.ipPtr->flags & NET_IP_MORE_FRAGS) {
  796.     if (ips_Debug) {
  797.         fprintf(stderr, "ReassemblePacket: More frags\n");
  798.     }
  799.     return(FALSE);
  800.     }
  801.  
  802.     /*
  803.      * At this point, all the fragments have been received. A new buffer
  804.      * is allocated so all the fragments can be concatenated together into
  805.      * 1 datagram.  The datagram's IP header comes from the first fragment.
  806.      * After copying the fragment, the FragDatInfo element is removed from
  807.      * the list and freed, along with the fragment.
  808.      *
  809.      * (IPS_InitPacket will resuse packetPtr and allocate new memory. 
  810.      * We don't free(packetPtr->base) before calling IPS_InitPacket 
  811.      * because that buffer is already used in one of elements in the fragment 
  812.      * data list for this datagram.)
  813.      */
  814.  
  815.     if (ips_Debug) {
  816.     fprintf(stderr, "ReassemblePacket: All frags received\n");
  817.     }
  818.  
  819.     IPS_InitPacket(next, packetPtr);
  820.     ptr = packetPtr->dbase + sizeof(IPS_PacketNetHdr);
  821.     packetPtr->ipPtr = (Net_IPHeader *) ptr;
  822.  
  823.     first = TRUE;
  824.     dataPtr = (FragDataInfo *) List_First(fragDataListPtr);
  825.     while (!List_IsAtEnd(fragDataListPtr, (List_Links *) dataPtr)) {
  826.     if (first) {
  827.         int amtToCopy = dataPtr->fragPacket.ipPtr->totalLen;
  828.         first = FALSE;
  829.  
  830.         /*
  831.          * The header of the first fragment needs to be copied, too.
  832.          */
  833.         bcopy((Address) dataPtr->fragPacket.ipPtr, (Address) ptr,amtToCopy);
  834.  
  835.         /*
  836.          * Reset the size of the packet in the header.
  837.          */
  838.         packetPtr->ipLen = ((Net_IPHeader *) ptr)->totalLen = 
  839.                 next + (dataPtr->fragPacket.ipPtr->headerLen * 4);
  840.  
  841.         ptr += amtToCopy;
  842.     } else {
  843.         bcopy((Address) dataPtr->fragPacket.ipPtr+dataPtr->dataOffset, 
  844.             (Address) ptr, dataPtr->dataLen);
  845.         ptr += dataPtr->dataLen;
  846.     }
  847.  
  848.     newDataPtr = (FragDataInfo *) (List_Next((List_Links *)dataPtr));
  849.     List_Remove((List_Links *) dataPtr);
  850.     free((char *) dataPtr->fragPacket.base);
  851.     free((char *) dataPtr);
  852.     dataPtr = newDataPtr;
  853.     }
  854.     List_Remove((List_Links *) fragInfoPtr);
  855.     free((char *) fragInfoPtr);
  856.  
  857.     return(TRUE);
  858. }
  859.  
  860. /*
  861.  *----------------------------------------------------------------------
  862.  *
  863.  * FreeFragments --
  864.  *
  865.  *    Releases the fragments held while trying to reassemble a datagram.
  866.  *
  867.  * Results:
  868.  *    Address of the previous element in the fragInfoList.
  869.  *
  870.  * Side effects:
  871.  *    The saved packets are freed and the *fragInfoPtr is removed
  872.  *    from the fragment queue.
  873.  *
  874.  *----------------------------------------------------------------------
  875.  */
  876.  
  877. static DgramFragInfo *
  878. FreeFragments(fragInfoPtr)
  879.     register DgramFragInfo *fragInfoPtr; /* Info about existing fragments
  880.                       * for this datagram. */
  881. {
  882.     register List_Links    *dataPtr;
  883.     register List_Links    *nextPtr;
  884.     DgramFragInfo *savePtr; 
  885.  
  886.     /*
  887.      * We need to return the ptr to the next element so this routine
  888.      * can be called inside of a list-examining loop and still be able 
  889.      * to remove the element from the list.
  890.      */
  891.     savePtr = (DgramFragInfo *) List_Next((List_Links *) fragInfoPtr);
  892.     List_Remove((List_Links *) fragInfoPtr);
  893.  
  894.     LIST_FORALL(&(fragInfoPtr->dataList), dataPtr) {
  895.     nextPtr = List_Next(dataPtr);
  896.     List_Remove(dataPtr);
  897.     free((char *) ((FragDataInfo *)dataPtr)->fragPacket.base);
  898.     free((char *) dataPtr);
  899.     dataPtr = nextPtr;
  900.     }
  901.     free((char *) fragInfoPtr);
  902.     return(savePtr);
  903. }
  904.  
  905.  
  906. /*
  907.  *----------------------------------------------------------------------
  908.  *
  909.  * ForwardPacket --
  910.  *
  911.  *    Given an packet that's not for us, this routine determines which 
  912.  *    host the packet should be forwarded to and tries to send it to
  913.  *    that host (possibly via gateways).
  914.  *
  915.  *    For now, we don't do forwarding -- the packet is just dropped.
  916.  *    This will need to change when Sprite machines want to act
  917.  *    as gateways/routers.
  918.  *
  919.  *
  920.  * Results:
  921.  *    None.
  922.  *
  923.  * Side effects:
  924.  *    None.
  925.  *
  926.  *----------------------------------------------------------------------
  927.  */
  928.  
  929. /*ARGSUSED*/
  930. static void
  931. ForwardPacket(packetPtr)
  932.     IPS_Packet    *packetPtr;    /* Packet layout descriptor. */
  933. {
  934.     stats.ip.cannotForward++;
  935. }
  936.  
  937.  
  938. /*
  939.  *----------------------------------------------------------------------
  940.  *
  941.  * ProcessOptions --
  942.  *
  943.  *    This routine decodes the option(s) that follow the IP header
  944.  *    and processes it/them.
  945.  *
  946.  * Results:
  947.  *    None.
  948.  *
  949.  * Side effects:
  950.  *    An ICMP packet is sent to the packet sender if if an option is 
  951.  *    malformed. The Record Route and Timestamp options modify the
  952.  *    the packet.
  953.  *
  954.  *----------------------------------------------------------------------
  955.  */
  956.  
  957. static ReturnStatus
  958. ProcessOptions(hdrLen, ipHeaderPtr)
  959.     int hdrLen;                /* Header length in bytes. */
  960.     register Net_IPHeader *ipHeaderPtr;    /* IP header with trailing options. */
  961. {
  962.     register Address optionPtr;        /* Ptr to the current option in the
  963.                      * IP header that's being processed. */
  964.     int        optionType;
  965.     int        optionLen;
  966.     int        totalOptionSize;
  967.     int        ptr;
  968.     int        icmpCode;
  969.     int        icmpType;
  970.  
  971.  
  972.     /*
  973.      * Go through the option area of the packet and process each option.
  974.      * The options begin just after the standard header info.
  975.      */
  976.     
  977.     optionPtr = ((Address) ipHeaderPtr) + sizeof(Net_IPHeader) + 1;
  978.  
  979.     for (totalOptionSize = hdrLen - sizeof(Net_IPHeader); 
  980.      totalOptionSize > 0; 
  981.      totalOptionSize -= optionLen, optionPtr += optionLen) {
  982.  
  983.     optionType = optionPtr[NET_IP_OPT_TYPE_OFFSET];
  984.  
  985.     /*
  986.      * Decode the option. END_OF_LIST and NOP options are only 1
  987.      * octet long. The rest of the options have a length field that 
  988.      * must be checked.
  989.      */
  990.  
  991.     if (optionType == NET_IP_OPT_END_OF_LIST) {
  992.         break;
  993.     } else if (optionType == NET_IP_OPT_NOP) {
  994.         optionLen = 1;
  995.     } else {
  996.         optionLen = optionPtr[NET_IP_OPT_LEN_OFFSET];
  997.         if (optionLen <= 0 || optionLen > totalOptionSize) {
  998.         icmpType = NET_ICMP_PARAM_PROB;
  999.         icmpCode = &optionPtr[NET_IP_OPT_LEN_OFFSET] - 
  1000.                 (Address) ipHeaderPtr;
  1001.         goto bad;
  1002.         }
  1003.  
  1004.         switch (optionType) {
  1005.  
  1006.         /*
  1007.          * Loose and strict source routing and record options:
  1008.          *
  1009.          * If the packet is not directed towards one of our
  1010.          * Internet addresses then send an ICMP error packet if
  1011.          * strict routing is wanted or do nothing if loosely
  1012.          * routed.  Also, record our address in the option area
  1013.          * and make the next address in the routing list as the
  1014.          * destination.  If strictly-routed, make sure the next
  1015.          * address is on a directly-accessible network.
  1016.          */
  1017.  
  1018.         case NET_IP_OPT_LOOSE_ROUTE:
  1019.         case NET_IP_OPT_STRICT_ROUTE:
  1020.  
  1021.             ptr = optionPtr[NET_IP_OPT_PTR_OFFSET];
  1022.             if (ptr < NET_IP_OPT_MIN_PTR) {
  1023.             icmpType = NET_ICMP_PARAM_PROB;
  1024.             icmpCode = &optionPtr[NET_IP_OPT_PTR_OFFSET]  -
  1025.                     (Address) ipHeaderPtr;
  1026.             goto bad;
  1027.             }
  1028.  
  1029.             if (!Rte_AddrIsForUs(ipHeaderPtr->dest)) {
  1030.             if (optionType == NET_IP_OPT_STRICT_ROUTE) {
  1031.                 icmpType = NET_ICMP_UNREACHABLE;
  1032.                 icmpCode = NET_ICMP_UNREACH_SRC_ROUTE;
  1033.                 goto bad;
  1034.             }
  1035.             /*
  1036.              * Loose routing, and not at next destination
  1037.              * yet; nothing to do except forward.
  1038.              */
  1039.             break;
  1040.             }
  1041.  
  1042.             ptr--;            /* 0 origin */
  1043.             if (ptr > optionLen - sizeof(Net_InetAddress)) {
  1044.             /*
  1045.              * End of source route.  Should be for us.
  1046.              */
  1047.             SaveRoute(optionPtr, ipHeaderPtr->source);
  1048.  
  1049.             } else {
  1050.             Net_InetAddress addr;
  1051.  
  1052.             /*
  1053.              * We are an intermediate host in the routing list.
  1054.              * Change the packet's destination to the next host in 
  1055.              * the list and record our address there.
  1056.              */
  1057.             addr = *((Net_InetAddress *)(optionPtr + ptr));
  1058.                 
  1059.             if ((optionType == NET_IP_OPT_STRICT_ROUTE) && 
  1060.                 !CanForward(addr)) {
  1061.                 icmpType = NET_ICMP_UNREACHABLE;
  1062.                 icmpCode = NET_ICMP_UNREACH_SRC_ROUTE;
  1063.                 goto bad;
  1064.             }
  1065.             *((Net_InetAddress *)(optionPtr + ptr)) =
  1066.                     (ipHeaderPtr->dest);
  1067.             optionPtr[NET_IP_OPT_PTR_OFFSET] += 
  1068.                     sizeof(Net_InetAddress);
  1069.             ipHeaderPtr->dest = addr;
  1070.             }
  1071.             break;
  1072.  
  1073.  
  1074.         /*
  1075.          * Record Route option: 
  1076.          *
  1077.          *  Add our address in the area reserved for routes.
  1078.          */
  1079.  
  1080.         case NET_IP_OPT_REC_ROUTE: 
  1081.             {
  1082.             ptr = optionPtr[NET_IP_OPT_PTR_OFFSET];
  1083.             if (ptr < NET_IP_OPT_MIN_PTR) {
  1084.                 icmpType = NET_ICMP_PARAM_PROB;
  1085.                 icmpCode= &optionPtr[NET_IP_OPT_PTR_OFFSET]  -
  1086.                     (Address) ipHeaderPtr;
  1087.                 goto bad;
  1088.             }
  1089.  
  1090.             /*
  1091.              * If no space remains, do nothing.
  1092.              */
  1093.             ptr--;            /* 0 origin */
  1094.             if (ptr <= (optionLen - sizeof(Net_InetAddress))) {
  1095.                 /*
  1096.                  * See if we can forward this packet before our
  1097.                  * address is recorded in the routing list.
  1098.                  */
  1099.  
  1100.                 if (!CanForward(ipHeaderPtr->dest)) {
  1101.                     icmpType = NET_ICMP_UNREACHABLE;
  1102.                     icmpCode = NET_ICMP_UNREACH_SRC_ROUTE;
  1103.                     goto bad;
  1104.                 }
  1105.                 *((Net_InetAddress *)(optionPtr + ptr)) =
  1106.                  (Rte_GetOfficialAddr(FALSE));
  1107.  
  1108.                 optionPtr[NET_IP_OPT_PTR_OFFSET] += 
  1109.                     sizeof(Net_InetAddress);
  1110.             }
  1111.             }
  1112.             break;
  1113.  
  1114.         /*
  1115.          * Timestamp option: 
  1116.          *
  1117.          * Add a timestamp (and optionally our address) in the area 
  1118.          * reserved for it.
  1119.          */
  1120.  
  1121.         case NET_IP_OPT_TIMESTAMP: 
  1122.             {
  1123.             Net_InetTime    time;
  1124.             Net_InetAddress *addrPtr;
  1125.             Net_IPTimestampHdr *tsPtr =
  1126.                     (Net_IPTimestampHdr *)optionPtr;
  1127.  
  1128.             if (tsPtr->len < 5) {
  1129.                 icmpType = NET_ICMP_PARAM_PROB;
  1130.                 icmpCode = optionPtr - (Address) ipHeaderPtr;
  1131.                 goto bad;
  1132.             }
  1133.  
  1134.             if (tsPtr->pointer > (tsPtr->len - sizeof(*tsPtr))) {
  1135.                 tsPtr->overflow++;
  1136.                 if (tsPtr->overflow == 0) {
  1137.                 icmpType = NET_ICMP_PARAM_PROB;
  1138.                 icmpCode = optionPtr - (Address) ipHeaderPtr;
  1139.                 goto bad;
  1140.                 }
  1141.                 break;
  1142.             }
  1143.  
  1144.             addrPtr = (Net_InetAddress *)
  1145.                     (optionPtr + tsPtr->pointer -1);
  1146.  
  1147.             switch (tsPtr->flags) {
  1148.  
  1149.                 case NET_IP_OPT_TS_ONLY:
  1150.                 break;
  1151.  
  1152.                 /*
  1153.                  * Add our address to the packet if there's room.
  1154.                  */
  1155.                 case NET_IP_OPT_TS_AND_ADDR:
  1156.                 if ((tsPtr->pointer + sizeof(Net_InetTime) +
  1157.                     sizeof(Net_InetAddress)) > tsPtr->len) {
  1158.                     icmpType = NET_ICMP_PARAM_PROB;
  1159.                     icmpCode = optionPtr -
  1160.                             (Address) ipHeaderPtr;
  1161.                     goto bad;
  1162.                 }
  1163.                 *addrPtr = (Rte_GetOfficialAddr(FALSE));
  1164.                 tsPtr->pointer += sizeof(*addrPtr);
  1165.                 break;
  1166.  
  1167.                 /*
  1168.                  * Add our address to the packet only if our
  1169.                  * address in the list of prespecified addresses.
  1170.                  */
  1171.                 case NET_IP_OPT_TS_ADDR_SPEC:
  1172.                 if ((tsPtr->pointer + sizeof(Net_InetTime) +
  1173.                     sizeof(Net_InetAddress)) > tsPtr->len) {
  1174.  
  1175.                     icmpType = NET_ICMP_PARAM_PROB;
  1176.                     icmpCode = optionPtr - 
  1177.                             (Address) ipHeaderPtr;
  1178.                     goto bad;
  1179.                 }
  1180.                 if (!Rte_AddrIsForUs((*addrPtr))) {
  1181.                     continue;
  1182.                 }
  1183.                 tsPtr->pointer += sizeof(*addrPtr);
  1184.                 break;
  1185.  
  1186.                 default:
  1187.                     /*
  1188.                      * Unknown timestamp flag.
  1189.                      */
  1190.                     icmpType = NET_ICMP_PARAM_PROB;
  1191.                     icmpCode = optionPtr -(Address) ipHeaderPtr;
  1192.                     goto bad;
  1193.             }
  1194.             time = Net_HostToNetInt(IPS_GetTimestamp());
  1195.             bcopy( (Address)&time, 
  1196.                       (Address) (optionPtr + tsPtr->pointer -1),
  1197.                   sizeof(time));
  1198.             tsPtr->pointer += sizeof(time);
  1199.             }
  1200.             break;
  1201.  
  1202.         /*
  1203.          * The following options aren't handled yet.
  1204.          */
  1205.         case NET_IP_OPT_STREAM_ID:
  1206.         case NET_IP_OPT_SECURITY:
  1207.         default:
  1208.             break;
  1209.         }
  1210.     }
  1211.     }
  1212.     return(SUCCESS);
  1213.  
  1214.     /*
  1215.      * We are sent here if there was an error with an option's format.
  1216.      * Send an ICMP error packet to the source.
  1217.      */
  1218. bad:
  1219.     ICMP_SendErrorMsg(ipHeaderPtr, icmpType, icmpCode);
  1220.     return (FAILURE);
  1221. }
  1222.  
  1223.  
  1224. /*
  1225.  *----------------------------------------------------------------------
  1226.  *
  1227.  * CanForward --
  1228.  *
  1229.  *     Given an address of the next destination (final or next hop),
  1230.  *     indicate whether we can foraward the packet.
  1231.  *
  1232.  * Results:
  1233.  *    TRUE    - we are able to forward the packet.
  1234.  *    FALSE    - we are not able to forward the packet.
  1235.  *
  1236.  * Side effects:
  1237.  *    None.
  1238.  *
  1239.  *----------------------------------------------------------------------
  1240.  */
  1241.  
  1242. /*ARGSUSED*/
  1243. static Boolean
  1244. CanForward(dest)
  1245.      Net_InetAddress dest;
  1246. {
  1247.     /*
  1248.      * For now, say we can't forward anything.
  1249.      */
  1250.     return(FALSE);
  1251. }
  1252.  
  1253.  
  1254. /*
  1255.  * We need to save the IP options in case a higher-level protocol wants 
  1256.  * to respond to an incoming packet over the same route if the packet got
  1257.  * here using IP source routing.  This allows connection establishment and
  1258.  * maintenance when the remote end is on a network that is not known to us.
  1259.  *
  1260.  * MAX_SAVE_ADDRS is the max. # of IP addresses that can be stored in
  1261.  * an IP record route option. Subtract 3 for the record route info (type,
  1262.  * length and pointer).
  1263.  */
  1264.  
  1265. #define MAX_SAVE_ADDRS  ((NET_IP_OPT_MAX_LEN - 3)/sizeof(Net_InetAddress))
  1266. static struct {
  1267.     int numHops;                /* # of addresses in addr. */
  1268.     struct {
  1269.     struct {
  1270.         char    nop;        /* One NOP to align when 
  1271.                      * returning the route. */
  1272.         char    type;        /* Option type */
  1273.         char    len;        /* Totol length of info + addr. */
  1274.         char    ptr;        /* Offset where routes start. */
  1275.     } info;
  1276.     Net_InetAddress addr[MAX_SAVE_ADDRS];    /* List of routes. */
  1277.     } route;
  1278.     Net_InetAddress     dest;        /* In host byte order. */
  1279. } savedSrcRoute = { 0, {{NET_IP_OPT_NOP,}, }, };
  1280.  
  1281. /*
  1282.  *----------------------------------------------------------------------
  1283.  *
  1284.  * SaveRoute --
  1285.  *
  1286.  *    Save incoming source route for use in replies,
  1287.  *    to be picked up later by IP_SrcRoute if the receiver is interested.
  1288.  *    The options are kept in network byte order.
  1289.  *
  1290.  *
  1291.  * Results:
  1292.  *    None.
  1293.  *
  1294.  * Side effects:
  1295.  *    The route is stored in a static buffer.
  1296.  *
  1297.  *----------------------------------------------------------------------
  1298.  */
  1299.  
  1300. static void
  1301. SaveRoute(optionPtr, dest)
  1302.     Address    optionPtr;    /* Ptr to IP options buffer containing source
  1303.                  * routing option. */
  1304.     Net_InetAddress dest;    /* Next destination address to put in the
  1305.                  * saved source route. */
  1306. {
  1307.     int optLen;
  1308.  
  1309.     optLen = optionPtr[NET_IP_OPT_LEN_OFFSET];
  1310.     if (optLen > sizeof(savedSrcRoute.route) - 1) {
  1311.     (void) fprintf(stderr, "Warning: SaveRoute (IP): optLen (%d) bad\n", optLen);
  1312.     return;
  1313.     }
  1314.     bcopy(optionPtr, (Address)&savedSrcRoute.route.info.type, optLen);
  1315.     savedSrcRoute.numHops = (optLen - 3) / sizeof(Net_InetAddress);
  1316.     savedSrcRoute.dest = dest;
  1317. }
  1318.  
  1319.  
  1320. /*
  1321.  *----------------------------------------------------------------------
  1322.  *
  1323.  * IP_GetSrcRoute --
  1324.  *
  1325.  *    Get the incoming source route that was saved in savedSrcRoute
  1326.  *    for use in replies. The first hop is returned in *destPtr.
  1327.  *
  1328.  * Results:
  1329.  *    The address of a buffer containing the saved source route from the
  1330.  *    most recent IP packet.
  1331.  *
  1332.  * Side effects:
  1333.  *    None.
  1334.  *
  1335.  *----------------------------------------------------------------------
  1336.  */
  1337.  
  1338. Address 
  1339. IP_GetSrcRoute(lenPtr, destPtr)
  1340.     int    *lenPtr;        /* Out: Size of source-route buffer. */
  1341.     Net_InetAddress *destPtr;    /* Out: address of the first destination. */
  1342. {
  1343.     register Net_InetAddress *oldPtr, *newPtr;
  1344.     register Address routePtr;
  1345.     int    len;
  1346.  
  1347.     if (savedSrcRoute.numHops == 0) {
  1348.     *lenPtr = 0;
  1349.     return((Address) NULL);
  1350.     }
  1351.  
  1352.     len = ((1 + savedSrcRoute.numHops) * sizeof(Net_InetAddress)) +
  1353.         sizeof(savedSrcRoute.route.info);
  1354.     *lenPtr = len;
  1355.  
  1356.     /*
  1357.      * Allocate a buffer to hold the source route.
  1358.      */
  1359.     routePtr = malloc((unsigned int) len);
  1360.  
  1361.     /*
  1362.      * First the save first hop for return route.
  1363.      */
  1364.     *destPtr = savedSrcRoute.dest;
  1365.  
  1366.     /*
  1367.      * Copy the route info.
  1368.      */
  1369.     bcopy( (Address) &savedSrcRoute.route.info, routePtr,
  1370.         sizeof(savedSrcRoute.route.info));
  1371.     newPtr = (Net_InetAddress *) (routePtr + sizeof(savedSrcRoute.route.info));
  1372.                 
  1373.     /*
  1374.      * Record return path as an IP source route, reversing the path.
  1375.      */
  1376.     oldPtr = &savedSrcRoute.route.addr[savedSrcRoute.numHops -1];
  1377.     while (oldPtr >= savedSrcRoute.route.addr) {
  1378.     *newPtr++ = *oldPtr--;
  1379.     }
  1380.     return(routePtr);
  1381. }
  1382.  
  1383.  
  1384. /*
  1385.  *----------------------------------------------------------------------
  1386.  *
  1387.  * IP_Output --
  1388.  *
  1389.  *    Causes an IP packet to sent to the network. The packet may be
  1390.  *    fragmented if it's too large for the chosen network.
  1391.  *
  1392.  * Results:
  1393.  *    SUCCESS            - the datagram was sent out.
  1394.  *    FS_BUFFER_TOO_BIG    - the datagram was too large and had to be
  1395.  *                  fragmented but the DONT_FRAG bit was set
  1396.  *                  in the header.
  1397.  *    NET_UNREACHABLE        - couldn't find a network to send the datagram
  1398.  *                  to.
  1399.  *
  1400.  * Side effects:
  1401.  *    Packet(s) may be output.
  1402.  *
  1403.  *----------------------------------------------------------------------
  1404.  */
  1405.  
  1406. ReturnStatus
  1407. IP_Output(packetPtr, canTrash)
  1408.     register IPS_Packet *packetPtr;    /* Packet layout descriptor. IP-related
  1409.                      * fields are filled in. If the packet
  1410.                      * is fragmented, the data and hdrLen
  1411.                      * fields are modified. */
  1412.     Boolean canTrash;            /* TRUE if the packet will be discarded
  1413.                      * after output.  If so, then we can
  1414.                      * optimize fragmentation by writing
  1415.                      * packet headers over some data. */
  1416. {
  1417.     ReturnStatus    status;
  1418.     int            headerLenInBytes;
  1419.     int            maxOutSize;
  1420.     Rte_NetID        netID;
  1421.     register Net_IPHeader *headerPtr = packetPtr->ipPtr;
  1422.  
  1423.  
  1424.     headerLenInBytes = headerPtr->headerLen * 4;
  1425.  
  1426.     if (headerLenInBytes > NET_IP_MAX_HDR_SIZE) {
  1427.     return(FAILURE);
  1428.     }
  1429.  
  1430.  
  1431.     /*
  1432.      * Determine which network interface must be used to output this
  1433.      * datagram.
  1434.      */
  1435.  
  1436.     if (!Rte_FindOutputNet(headerPtr->dest,  &netID, &maxOutSize)) {
  1437.     return(NET_UNREACHABLE_NET);
  1438.     }
  1439.  
  1440. #ifdef notdef
  1441.     headerPtr->source = Net_HostToNetInt(headerPtr->source);
  1442.     headerPtr->dest   = Net_HostToNetInt(headerPtr->dest);
  1443. #endif
  1444.  
  1445.     /*
  1446.      * See if the datagram is small enough to be sent in 1 piece.
  1447.      */
  1448.  
  1449.     if (headerPtr->totalLen <= maxOutSize) {
  1450.     int    totalLen;
  1451.  
  1452.     stats.ip.wholeSent++;
  1453.     totalLen = headerPtr->totalLen;
  1454.     headerPtr->totalLen = Net_HostToNetShort(totalLen);
  1455.     headerPtr->fragOffset = 0;
  1456.     headerPtr->flags = 0;
  1457.     headerPtr->checksum = 0;
  1458.     headerPtr->checksum = Net_InetChecksum(headerLenInBytes, 
  1459.                     (Address) headerPtr);
  1460.     packetPtr->ipLen = headerLenInBytes;
  1461.     status = Rte_OutputPacket(netID, packetPtr);
  1462.  
  1463.     } else if (headerPtr->flags & NET_IP_DONT_FRAG) {
  1464.     /*
  1465.      * The datagram is too big but the higher-level protocol doesn't want
  1466.      * it to be fragmented. Better tell the sender that it's too big.
  1467.      */
  1468.  
  1469.     stats.ip.dontFragment++;
  1470.  
  1471.     status = FS_BUFFER_TOO_BIG;
  1472.     } else {
  1473.  
  1474.     register Address fragPtr;
  1475.     register Address dataPtr;
  1476.     int        totalDataLen;
  1477.     int        fragDataLen;
  1478.     int        fragHdrLen;
  1479.     int        offset;
  1480.     IPS_Packet     packet;
  1481.     char        ipHeader[NET_IP_MAX_HDR_SIZE];
  1482.  
  1483.     stats.ip.fragOnSend++;
  1484.  
  1485.     /*
  1486.      * The datagram is too big to send as 1 packet on the network
  1487.      * (identified by netID) but we can fragment the datagram into 
  1488.      * several packets and send them out individually. 
  1489.      *
  1490.      * Each fragment contains an IP header based on the original
  1491.      * header plus some portion of the data.  Options in the IP header
  1492.      * require special handling. All options in the original header
  1493.      * need to go in the first fragment's header.  In succeeding
  1494.      * fragments, only some of the options are included in the header.
  1495.      *
  1496.      * TotalDataLen is the number of bytes of data in the datagram and
  1497.      * fragDataLen is the amount of data that can fit into a fragment.
  1498.      * Actually fragDataLen must be a multiple of 8 (c.f. p. 25 in RFC791);
  1499.      * this done by masking off the low-order 3 bits.
  1500.      */
  1501.  
  1502.     totalDataLen = headerPtr->totalLen - headerLenInBytes;
  1503.     fragDataLen = (maxOutSize - headerLenInBytes) & ~7;
  1504.  
  1505.     /*
  1506.      * Output the first fragment. We use the orginal datagram by modifying 
  1507.      * the header and telling the output routine how many bytes to output 
  1508.      * so we can avoid copying.
  1509.      */
  1510.  
  1511.     headerPtr->flags = NET_IP_MORE_FRAGS;
  1512.     headerPtr->fragOffset = 0;
  1513.     SWAP_FRAG_OFFSET_HOST_TO_NET(headerPtr);
  1514.  
  1515.     headerPtr->totalLen = Net_HostToNetShort(fragDataLen+headerLenInBytes);
  1516.     headerPtr->checksum = 0;
  1517.     headerPtr->checksum = Net_InetChecksum(headerLenInBytes, 
  1518.                     (Address) headerPtr);
  1519.     packetPtr->dataLen = fragDataLen;
  1520.     packetPtr->ipLen = headerLenInBytes;
  1521.  
  1522.     /*
  1523.      * Reset the packet's higher-level protocol header length to 0.
  1524.      * That header is now considered part of the data.
  1525.      */
  1526.     packetPtr->hdrLen = 0;
  1527.     status = Rte_OutputPacket(netID, packetPtr);
  1528.     stats.ip.fragsSent++;
  1529.     if (status != SUCCESS) {
  1530.         return(status);
  1531.     }
  1532.  
  1533.     /*
  1534.      * The first fragDataLen bytes have been sent. DataPtr is set to
  1535.      * point to the next byte in the original datagram to be sent.
  1536.      */
  1537.     dataPtr = (Address) (((Address) headerPtr) + headerLenInBytes + 
  1538.                 fragDataLen);
  1539.  
  1540.     /*
  1541.      * Now allocate a buffer that will be used to send the rest of the
  1542.      * fragments.  We must over-allocate the space because we don't
  1543.      * know how much room the header options need until we copy them
  1544.      * (only some options are copied). The rest of the buffer will 
  1545.      * hold part of the data from the original packet.  We reuse this 
  1546.      * buffer for all remaining fragments, adjusting the header if 
  1547.      * necessary.
  1548.      *
  1549.      * CAN_TRASH:  If we can trash the packet then we do so by writing
  1550.      * the fragment headers over existing data.  This eliminates the
  1551.      * need to allocate a buffer and copy data into it.  The variable
  1552.      * dataPtr always references the next data byte to be output.
  1553.      * packet.base is set to be in front of this enough to fit the header.
  1554.      */
  1555.  
  1556. #define fragHdrPtr ((Net_IPHeader *)fragPtr)
  1557.  
  1558.     packet.totalLen = fragDataLen + headerLenInBytes + 
  1559.                    sizeof(IPS_PacketNetHdr);
  1560.     packet.hdrLen = 0;
  1561.     if (!canTrash) {
  1562.         /*
  1563.          * Allocate a packet buffer and copy the header into it.  Note that
  1564.          * we add two the allocated pointer so that we four byte align
  1565.          * everything but the 14 byte ethernet header.
  1566.          */
  1567.         packet.base = malloc((unsigned int) packet.totalLen + 2);
  1568.         packet.dbase = packet.base + 2;
  1569.         fragPtr = packet.dbase + sizeof(IPS_PacketNetHdr);
  1570.         fragHdrLen = CopyHeader(headerLenInBytes, headerPtr, 
  1571.                     (Net_IPHeader *)fragPtr);
  1572.         packet.ipPtr = fragHdrPtr;
  1573.         fragHdrPtr->headerLen = fragHdrLen / 4;
  1574.     } else {
  1575.         /*
  1576.          * Just save the fragment header and get its length.
  1577.          */
  1578.         fragHdrLen = CopyHeader(headerLenInBytes, headerPtr, ipHeader);
  1579.     }
  1580.     packet.ipLen = fragHdrLen;
  1581.  
  1582.     for (offset = fragDataLen; 
  1583.          offset < totalDataLen; 
  1584.          offset += fragDataLen, dataPtr += fragDataLen) {
  1585.  
  1586.         if (canTrash) {
  1587.         /*
  1588.          * Copy the fragment header in front of the next data to go out.
  1589.          */
  1590.         fragPtr = dataPtr - fragHdrLen;
  1591.         bcopy((char *)ipHeader, fragPtr, fragHdrLen);
  1592.         packet.base = packet.dbase = fragPtr - sizeof(IPS_PacketNetHdr);
  1593.         packet.ipPtr = fragHdrPtr;
  1594.         fragHdrPtr->headerLen = fragHdrLen / 4;
  1595.         }
  1596.         if (offset + fragDataLen >= totalDataLen) {
  1597.         /*
  1598.          * Last fragment reached. Must turn off MORE_FRAGS so the
  1599.          * receiver won't expect more data.
  1600.          */
  1601.         fragDataLen =  totalDataLen - offset;
  1602.         fragHdrPtr->flags = 0;
  1603.         } else {
  1604.         fragHdrPtr->flags = NET_IP_MORE_FRAGS;
  1605.         }
  1606.         fragHdrPtr->fragOffset = offset >> 3;
  1607.         SWAP_FRAG_OFFSET_HOST_TO_NET(fragHdrPtr);
  1608.  
  1609.         fragHdrPtr->totalLen = Net_HostToNetShort(fragDataLen + fragHdrLen);
  1610.  
  1611.  
  1612.         if (!canTrash) {
  1613.         /*
  1614.          * Copy the data into the extra packet.
  1615.          */
  1616.         bcopy( (Address) dataPtr, 
  1617.             (Address) fragPtr+fragHdrLen, fragDataLen);
  1618.         }
  1619.  
  1620.         fragHdrPtr->checksum = 0;
  1621.         fragHdrPtr->checksum = Net_InetChecksum(fragHdrLen, 
  1622.                         (Address) fragHdrPtr);
  1623.         packet.data = fragPtr + packet.ipLen;
  1624.         packet.dataLen = fragDataLen;
  1625.         status = Rte_OutputPacket(netID, &packet);
  1626.         stats.ip.fragsSent++;
  1627.         if (status != SUCCESS) {
  1628.         break;
  1629.         }
  1630.     }
  1631.     if (!canTrash) {
  1632.         free(packet.base);
  1633.     }
  1634.     }
  1635.     return (status);
  1636. }
  1637.  
  1638.  
  1639. /*
  1640.  *----------------------------------------------------------------------
  1641.  *
  1642.  * IP_QueueOutput --
  1643.  *
  1644.  *    Queues up a packet to be sent at a later time by IP_DelayedOutput.
  1645.  *
  1646.  * Results:
  1647.  *    None.
  1648.  *
  1649.  * Side effects:
  1650.  *    A queued packet may be sent.
  1651.  *    The packet is freed once IP_Output is called.
  1652.  *
  1653.  *----------------------------------------------------------------------
  1654.  */
  1655.  
  1656. static IPS_Packet queuedPacket;
  1657. static Boolean     isPacketQueued = FALSE;
  1658.  
  1659. void
  1660. IP_QueueOutput(packetPtr)
  1661.     IPS_Packet *packetPtr;    /* Packet layout descriptor. */
  1662. {
  1663.     if (isPacketQueued) {
  1664.     isPacketQueued = FALSE;
  1665.     (void) IP_Output(&queuedPacket, TRUE);
  1666.     free(queuedPacket.base);
  1667.  
  1668.     (void) IP_Output(packetPtr, TRUE);
  1669.     free(packetPtr->base);
  1670.     } else {
  1671.     isPacketQueued = TRUE;
  1672.     queuedPacket = *packetPtr;
  1673.     }
  1674. }
  1675.  
  1676.  
  1677. /*
  1678.  *----------------------------------------------------------------------
  1679.  *
  1680.  * IP_DelayedOutput --
  1681.  *
  1682.  *    Causes a queued IP packet to be output.
  1683.  *
  1684.  * Results:
  1685.  *    None.
  1686.  *
  1687.  * Side effects:
  1688.  *    The packet is freed once IP_Output is called.
  1689.  *
  1690.  *----------------------------------------------------------------------
  1691.  */
  1692.  
  1693. void
  1694. IP_DelayedOutput()
  1695. {
  1696.     if (isPacketQueued) {
  1697.     isPacketQueued = FALSE;
  1698.     (void) IP_Output(&queuedPacket, TRUE);
  1699.     free(queuedPacket.base);
  1700.     }
  1701. }
  1702.  
  1703.  
  1704. /*
  1705.  *----------------------------------------------------------------------
  1706.  *
  1707.  * CopyHeader --
  1708.  *
  1709.  *    Copies the IP header from a unfragmented datagram to a fragmented
  1710.  *    datagram. The basic IP header is copied from the source datagram 
  1711.  *    along with some of the options to the destination datagram.
  1712.  *    According to RFC791, only certain options are copied to fragment
  1713.  *    headers.
  1714.  *
  1715.  * Results:
  1716.  *    The length in bytes of the copied header.
  1717.  *
  1718.  * Side effects:
  1719.  *    None.
  1720.  *
  1721.  *----------------------------------------------------------------------
  1722.  */
  1723.  
  1724. static int
  1725. CopyHeader(srcHdrLen, srcHdrPtr, destHdrPtr)
  1726.     int        srcHdrLen;        /* # of bytes in the src header. */
  1727.     Net_IPHeader *srcHdrPtr;        /* Ptr to original datagram header. */
  1728.     Net_IPHeader *destHdrPtr;        /* Ptr to fragment datagram header. */
  1729. {
  1730.     register unsigned char *srcPtr;    /* Ptr to the source's options area. */
  1731.     register unsigned char *destPtr;    /* Ptr to the dest's options area. */
  1732.     int        optionAreaLen;        /* # of bytes of options that have been
  1733.                      * copied from the source to dest. */
  1734.     int        option;            /* Current option. */
  1735.     int        optionLen;        /* Lenght in bytes of current option.*/
  1736.  
  1737.     /*
  1738.      * First copy the basic IP header that is required for every IP datagram.
  1739.      */
  1740.     *destHdrPtr = *srcHdrPtr;
  1741.  
  1742.     /*
  1743.      * Now selectively copy options from the source packet to the dest
  1744.      * packet header. The dest packet is a fragment and only some of the
  1745.      * options need to be copied to it.
  1746.      */
  1747.     srcPtr  = (unsigned char *)((Address)srcHdrPtr  + sizeof(Net_IPHeader));
  1748.     destPtr = (unsigned char *)((Address)destHdrPtr + sizeof(Net_IPHeader));
  1749.  
  1750.     optionAreaLen = srcHdrLen - sizeof(Net_IPHeader);
  1751.  
  1752.     for ( ; optionAreaLen > 0; optionAreaLen -= optionLen, srcPtr += optionLen){
  1753.         option = srcPtr[0];
  1754.         if (option == NET_IP_OPT_END_OF_LIST) {
  1755.         break;
  1756.         }
  1757.         if (option == NET_IP_OPT_NOP) {
  1758.         optionLen = 1;
  1759.         } else {
  1760.         optionLen = srcPtr[NET_IP_OPT_LEN_OFFSET];
  1761.         }
  1762.  
  1763.         if (optionLen > optionAreaLen) {
  1764.         (void) fprintf(stderr, 
  1765.             "Warning: (IP) CopyOption: bad option length %d\n", 
  1766.             optionLen);
  1767.         optionLen = optionAreaLen;
  1768.         }
  1769.  
  1770.         /*
  1771.          * Copy the option if it's supposed to be copied.
  1772.          */
  1773.         if (NET_IP_OPT_COPIED(option)) {
  1774.         bcopy((Address)srcPtr, (Address)destPtr, optionLen);
  1775.         destPtr += optionLen;
  1776.         }
  1777.     }
  1778.  
  1779.     /*
  1780.      * Pad the options area in the dest. packet with END_OF_LIST until 
  1781.      * a 32-bit boundary is reached.
  1782.      */
  1783.     for (optionLen = destPtr - (unsigned char *)(destHdrPtr+1); 
  1784.          optionLen & 0x3; optionLen++) {
  1785.     *destPtr++ = NET_IP_OPT_END_OF_LIST;
  1786.     }
  1787.  
  1788.     /*
  1789.      * Return the true size of the dest.'s datagram header.
  1790.      */
  1791.     return(sizeof(Net_IPHeader) + optionLen);
  1792. }
  1793.  
  1794.  
  1795. /*
  1796.  *----------------------------------------------------------------------
  1797.  *
  1798.  * IP_FormatPacket --
  1799.  *
  1800.  *    Given a partially-formed packet, this routine fills in most
  1801.  *    of the fields in the IP header and computes a checksum for
  1802.  *    the header. After this routine completes, the packet can be
  1803.  *    sent out on the network.
  1804.  *
  1805.  * Results:
  1806.  *    None.
  1807.  *
  1808.  * Side effects:
  1809.  *    All IP fields in the packet are modified.
  1810.  *
  1811.  *----------------------------------------------------------------------
  1812.  */
  1813.  
  1814. void
  1815. IP_FormatPacket(protocol, timeToLive, srcAddr, destAddr, packetPtr)
  1816.     int            protocol;    /* Assigned protocol #. */
  1817.     int            timeToLive;    /* # of seconds before packet should
  1818.                      * be discarded. Value depends on
  1819.                      * the protocol. */
  1820.     Net_InetAddress    srcAddr;    /* One of our IP addresses. */
  1821.     Net_InetAddress    destAddr;    /* Where to send the packet. */
  1822.     register IPS_Packet *packetPtr;    /* Partially formed packet. */
  1823. {
  1824.     register Net_IPHeader    *ipPtr;
  1825.     static int    ident = 0;
  1826.  
  1827.     /*
  1828.      * Fill in the IP-specific stuff in the packet.
  1829.      */
  1830.     packetPtr->ipLen = sizeof(Net_IPHeader);
  1831.     if (packetPtr->hdrLen > 0) {
  1832.     ipPtr = packetPtr->ipPtr = (Net_IPHeader *) 
  1833.             (((Address)packetPtr->hdr.hdrPtr) - packetPtr->ipLen);
  1834.     } else {
  1835.     ipPtr = packetPtr->ipPtr = (Net_IPHeader *) 
  1836.             (packetPtr->data - packetPtr->ipLen);
  1837.     }
  1838.  
  1839.     /*
  1840.      * Fill in the IP header and checksum it.
  1841.      */
  1842.     ipPtr->version    = NET_IP_VERSION;
  1843.     ipPtr->headerLen    = sizeof(Net_IPHeader) / 4;
  1844.     ipPtr->typeOfService = 0;
  1845.     ipPtr->totalLen    = sizeof(Net_IPHeader) + packetPtr->hdrLen + 
  1846.                 packetPtr->dataLen;
  1847.     ipPtr->ident    = Net_HostToNetShort(ident);
  1848.     ident += 1;
  1849.     ipPtr->fragOffset    = 0;
  1850.     ipPtr->flags    = 0;
  1851.     ipPtr->timeToLive    = timeToLive;
  1852.     ipPtr->protocol    = protocol;
  1853.     ipPtr->source    = srcAddr;
  1854.     ipPtr->dest        = destAddr;
  1855.     ipPtr->checksum    = 0;
  1856.     ipPtr->checksum    = Net_InetChecksum(sizeof(Net_IPHeader),(Address)ipPtr);
  1857. }
  1858.  
  1859.  
  1860. /*
  1861.  *----------------------------------------------------------------------
  1862.  *
  1863.  * TestInputProc --
  1864.  *
  1865.  *    Debugging code to print the header of an IP datagram.
  1866.  *
  1867.  * Results:
  1868.  *    None.
  1869.  *
  1870.  * Side effects:
  1871.  *    None.
  1872.  *
  1873.  *----------------------------------------------------------------------
  1874.  */
  1875.  
  1876. #ifdef DEBUG
  1877.  
  1878. static char srcAddr[18];
  1879. static char destAddr[18];
  1880. static char *ProtNumToName();
  1881.  
  1882. /*ARGSUSED*/
  1883. static void
  1884. TestInputProc(netID, packetPtr)
  1885.     Rte_NetID    netID;
  1886.     IPS_Packet    *packetPtr;
  1887. {
  1888.     register Net_IPHeader       *headerPtr;
  1889.     unsigned short        checksum;
  1890.  
  1891.     headerPtr = packetPtr->ipPtr;
  1892.  
  1893.     (void) fflush(stdout);
  1894.  
  1895.     (void) Net_InetAddrToString(headerPtr->source, srcAddr);
  1896.     (void) Net_InetAddrToString(headerPtr->dest, destAddr);
  1897.  
  1898.     (void) printf("IP Packet: size = %d\n", packetPtr->ipLen);
  1899.     (void) printf("Protocol, version:    %s, %d\n", 
  1900.             ProtNumToName(headerPtr->protocol),
  1901.             headerPtr->version);
  1902.     (void) printf("Src, dest addrs:    %s, %s\n", srcAddr, destAddr);
  1903.  
  1904.     (void) printf("Header, total len:    %d, %d\n", 
  1905.             headerPtr->headerLen, headerPtr->totalLen);
  1906.     (void) printf("TOS, ttl:        %x, %d\n", 
  1907.             headerPtr->typeOfService, headerPtr->timeToLive);
  1908.     checksum = headerPtr->checksum, 
  1909.     headerPtr->checksum = 0;
  1910.     (void) printf("checksum, recomp:    %x, %x\n", checksum, 
  1911.         Net_InetChecksum((int)headerPtr->headerLen*4, 
  1912.                     (Address)headerPtr));
  1913.     (void) printf("Frag flags, offset, ID:    %x, %d, %x\n", 
  1914.             headerPtr->flags, headerPtr->fragOffset, 
  1915.             headerPtr->ident);
  1916.     (void) printf("\n");
  1917.  
  1918.     (void) fflush(stdout);
  1919.  
  1920.     free(packetPtr->base);
  1921.     return;
  1922. }
  1923.  
  1924. static char *
  1925. ProtNumToName(num) 
  1926.     unsigned char num;
  1927. {
  1928.     static char buffer[5];
  1929.  
  1930.     switch (num) {
  1931.     case NET_IP_PROTOCOL_IP:
  1932.         return("IP");
  1933.     case NET_IP_PROTOCOL_ICMP:
  1934.         return("ICMP");
  1935.     case NET_IP_PROTOCOL_TCP:
  1936.         return("TCP");
  1937.     case NET_IP_PROTOCOL_EGP:
  1938.         return("EGP");
  1939.     case NET_IP_PROTOCOL_UDP:
  1940.         return("UDP");
  1941.     default:
  1942. #ifndef KERNEL
  1943.         (void) sprintf(buffer, "%4d", num);
  1944.         return(buffer);
  1945. #else
  1946.         return("???");
  1947. #endif
  1948.     }
  1949. }
  1950. #endif DEBUG
  1951.